﻿/*
 * Copyright © 2025−2026 CST Information Technology Co., Ltd. (Chengdu). All rights reserved.
 *
 * THIS SOURCE CODE IS PROPRIETARY AND CONFIDENTIAL.
 * It is the exclusive property of CST and may not be
 * used, copied, distributed, or disclosed outside of CST
 * without express written permission.
 *
 * This code is provided under a limited, non-transferable internal license
 * to authorized employees of CST for company-approved
 * purposes only. No external license is granted or implied.
 *
 * Any unauthorized use, reproduction, or distribution is strictly prohibited
 * and may result in severe civil and criminal penalties.
 */

using Aore.Utility.IdGenerator.SnowflakeId;

namespace Aore.Utility.IdGenerator.CurrentTransId;

public class CurrentTransIdGenerator
{
  // 为每个应用实例分配一个唯一的 workerId，例如通过配置、环境变量或注册中心获取
  private static readonly SnowflakeIdGenerator _generator = new(workerId: 1);


  // _lockObjectByThread 仍然是必要的，用于保护整个 ID 生成逻辑
  private static readonly object _lockObjectByThread = new();

  // 记录上一次生成 ID 的完整时间戳 (Ticks 包含纳秒精度)
  private static long _lastTicks;

  // 记录当前时间戳下的序列号
  private static int _sequenceCounter;

  /// <summary>
  /// 获取TransID,基于时间戳与雪花Id
  /// </summary>
  /// <returns></returns>
  public static string CurrentTransIdGeneratorSnowflake()
  {
    long id = _generator.NextId();
    DateTime now = DateTime.Now;
    // 将时间与 Snowflake 产生的长整型拼接成字符串；长度可按需调整
    return $"A{now:yyyyMMddHHmmssffff}{Convert.ToString(id).ToUpper()}";
  }
  
  /// <summary>
  ///  [線程安全] 获取TransID，基于时间戳
  /// </summary>
  /// <returns>TransID</returns>
  public static string CurrentTransId()
  {
    try
    {
      lock (_lockObjectByThread)
      {
        // 获取当前时间的 Ticks (100纳秒间隔)
        // DateTime.Now.Ticks 提供了比 DateTime.Now.Millisecond 更高的精度，
        // 但我们的目标是生成 23 位的 ID，并且要避免重复。
        // 格式 "yyyyMMddHHmmssffff" 实际上是到毫秒。
        // 所以我们主要关注毫秒级的变化。

        DateTime currentDateTime = DateTime.Now;
        int currentMilliseconds = currentDateTime.Millisecond;

        // 如果当前毫秒与上一次不同
        if (currentDateTime.Ticks != _lastTicks)
        {
          // 重置序列号，并更新上一次的时间戳
          _sequenceCounter = 0;
          _lastTicks = currentDateTime.Ticks;
        }
        else
        {
          // 如果是同一个毫秒，并且序列号已经达到了 D4 的上限 (9999)
          // 理论上，如果并发量极大，可能在同一毫秒内耗尽 10000 个 ID。
          // 此时我们需要等待到下一个毫秒。
          if (_sequenceCounter >= 9999)
          {
            // 等待下一个毫秒
            // 这种等待可能会引入延迟，但能保证唯一性。
            // 更优的策略是直接轮询直到下一个毫秒，但要小心死锁。
            // 这里使用一个简化的等待，如果非常频繁出现，需要更复杂的机制。

            // 简单地轮询直到时间变化
            while (DateTime.Now.Millisecond == currentMilliseconds && DateTime.Now.Ticks == _lastTicks)
            {
              Thread.Sleep(1); // 短暂休眠，释放 CPU
            }
            // 时间已经变化，重置并获取新时间戳
            currentDateTime = DateTime.Now;
            _lastTicks = currentDateTime.Ticks;
            _sequenceCounter = 0; // 重置序列号
          }
          else
          {
            // 在同一个毫秒内，递增序列号
            _sequenceCounter++;
          }
        }

        // 格式化 ID: A + 时间戳 + 序列号 (4位补零)
        // yyyyMMddHHmmssffff 已经包含了毫秒，所以可以直接使用
        return $"A{currentDateTime.ToString("yyyyMMddHHmmssffff")}{_sequenceCounter:D4}";
      }
    }
    catch (Exception e)
    {
      // 记录日志更合适，避免直接抛出 Exception
      // LogHelper.Error($"Get current trans id failed! [{e.Message}]", e);
      throw new Exception($"Get current trans id failed! [{e.Message}]", e);
    }
  }
}